#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
交易成本模拟器
Trading Cost Simulator

专业级回测功能升级 - 交易成本模拟组件
支持手续费、滑点、冲击成本等真实交易成本模拟

作者: 后端工程师 + 量化分析师
日期: 2025-08-04
"""

import logging
import numpy as np
import pandas as pd
from datetime import datetime
from typing import Dict, List, Optional, Any, Tuple
from dataclasses import dataclass
from enum import Enum
import math

logger = logging.getLogger('户部尚赢.专业回测.交易成本模拟器')

class OrderSide(Enum):
    """订单方向"""
    BUY = "buy"
    SELL = "sell"

class SlippageModel(Enum):
    """滑点模型"""
    LINEAR = "linear"
    SQUARE_ROOT = "square_root"
    ADAPTIVE = "adaptive"

@dataclass
class Order:
    """订单类"""
    stock_code: str
    side: OrderSide
    quantity: int
    price: float
    timestamp: datetime
    order_value: float = 0.0
    
    def __post_init__(self):
        self.order_value = self.quantity * self.price

@dataclass
class TradingCostConfig:
    """交易成本配置"""
    # 手续费配置
    commission_rate: float = 0.0003  # 万三佣金
    min_commission: float = 5.0      # 最低佣金5元
    stamp_tax_rate: float = 0.001    # 千一印花税（仅卖出）
    transfer_fee_rate: float = 0.00002  # 万0.2过户费
    
    # 滑点配置
    slippage_model: SlippageModel = SlippageModel.LINEAR
    base_slippage_bps: float = 2.0   # 基础滑点2个基点
    volume_impact_factor: float = 0.1  # 成交量冲击因子
    
    # 市场冲击配置
    temporary_impact_factor: float = 0.5  # 临时冲击因子
    permanent_impact_factor: float = 0.3  # 永久冲击因子
    liquidity_threshold: float = 0.1      # 流动性阈值（占日成交量比例）

@dataclass
class TradingCostResult:
    """交易成本结果"""
    commission: float = 0.0
    stamp_tax: float = 0.0
    transfer_fee: float = 0.0
    slippage_cost: float = 0.0
    market_impact_cost: float = 0.0
    total_cost: float = 0.0
    effective_price: float = 0.0
    cost_bps: float = 0.0  # 成本基点

class TradingCostSimulator:
    """交易成本模拟器"""
    
    def __init__(self, config: TradingCostConfig = None):
        """初始化交易成本模拟器"""
        self.config = config or TradingCostConfig()
        self.market_data_cache = {}
        self.daily_volume_cache = {}
        
        logger.info("✅ 交易成本模拟器初始化完成")
    
    def calculate_transaction_cost(self, order: Order, market_data: Dict = None) -> TradingCostResult:
        """计算交易成本"""
        try:
            result = TradingCostResult()
            
            # 1. 计算手续费
            result.commission = self._calculate_commission(order)
            
            # 2. 计算印花税（仅卖出）
            result.stamp_tax = self._calculate_stamp_tax(order)
            
            # 3. 计算过户费
            result.transfer_fee = self._calculate_transfer_fee(order)
            
            # 4. 计算滑点成本
            result.slippage_cost = self._calculate_slippage_cost(order, market_data)
            
            # 5. 计算市场冲击成本
            result.market_impact_cost = self._calculate_market_impact_cost(order, market_data)
            
            # 6. 计算总成本
            result.total_cost = (result.commission + result.stamp_tax + 
                               result.transfer_fee + result.slippage_cost + 
                               result.market_impact_cost)
            
            # 7. 计算有效价格
            if order.side == OrderSide.BUY:
                result.effective_price = order.price + (result.total_cost / order.quantity)
            else:
                result.effective_price = order.price - (result.total_cost / order.quantity)
            
            # 8. 计算成本基点
            result.cost_bps = (result.total_cost / order.order_value) * 10000
            
            logger.debug(f"交易成本计算完成: {order.stock_code} - 总成本: {result.total_cost:.2f}元 ({result.cost_bps:.2f}bps)")
            
            return result
            
        except Exception as e:
            logger.error(f"❌ 计算交易成本失败: {e}")
            return TradingCostResult()
    
    def _calculate_commission(self, order: Order) -> float:
        """计算佣金"""
        try:
            commission = order.order_value * self.config.commission_rate
            return max(commission, self.config.min_commission)
            
        except Exception as e:
            logger.error(f"❌ 计算佣金失败: {e}")
            return 0.0
    
    def _calculate_stamp_tax(self, order: Order) -> float:
        """计算印花税（仅卖出）"""
        try:
            if order.side == OrderSide.SELL:
                return order.order_value * self.config.stamp_tax_rate
            return 0.0
            
        except Exception as e:
            logger.error(f"❌ 计算印花税失败: {e}")
            return 0.0
    
    def _calculate_transfer_fee(self, order: Order) -> float:
        """计算过户费"""
        try:
            return order.order_value * self.config.transfer_fee_rate
            
        except Exception as e:
            logger.error(f"❌ 计算过户费失败: {e}")
            return 0.0
    
    def _calculate_slippage_cost(self, order: Order, market_data: Dict = None) -> float:
        """计算滑点成本"""
        try:
            if not market_data:
                # 使用基础滑点
                slippage_rate = self.config.base_slippage_bps / 10000
                return order.order_value * slippage_rate
            
            # 根据滑点模型计算
            if self.config.slippage_model == SlippageModel.LINEAR:
                return self._calculate_linear_slippage(order, market_data)
            elif self.config.slippage_model == SlippageModel.SQUARE_ROOT:
                return self._calculate_sqrt_slippage(order, market_data)
            elif self.config.slippage_model == SlippageModel.ADAPTIVE:
                return self._calculate_adaptive_slippage(order, market_data)
            else:
                return order.order_value * (self.config.base_slippage_bps / 10000)
                
        except Exception as e:
            logger.error(f"❌ 计算滑点成本失败: {e}")
            return 0.0
    
    def _calculate_linear_slippage(self, order: Order, market_data: Dict) -> float:
        """计算线性滑点"""
        try:
            # 获取市场数据
            bid_ask_spread = market_data.get('bid_ask_spread', 0.01)
            daily_volume = market_data.get('volume', 1000000)
            
            # 计算订单占日成交量比例
            volume_ratio = (order.quantity * order.price) / (daily_volume * order.price)
            
            # 线性滑点模型
            base_slippage = self.config.base_slippage_bps / 10000
            volume_impact = volume_ratio * self.config.volume_impact_factor
            spread_impact = bid_ask_spread / order.price * 0.5
            
            total_slippage_rate = base_slippage + volume_impact + spread_impact
            
            return order.order_value * total_slippage_rate
            
        except Exception as e:
            logger.error(f"❌ 计算线性滑点失败: {e}")
            return 0.0
    
    def _calculate_sqrt_slippage(self, order: Order, market_data: Dict) -> float:
        """计算平方根滑点"""
        try:
            daily_volume = market_data.get('volume', 1000000)
            volume_ratio = (order.quantity * order.price) / (daily_volume * order.price)
            
            # 平方根滑点模型
            base_slippage = self.config.base_slippage_bps / 10000
            sqrt_impact = math.sqrt(volume_ratio) * self.config.volume_impact_factor
            
            total_slippage_rate = base_slippage + sqrt_impact
            
            return order.order_value * total_slippage_rate
            
        except Exception as e:
            logger.error(f"❌ 计算平方根滑点失败: {e}")
            return 0.0
    
    def _calculate_adaptive_slippage(self, order: Order, market_data: Dict) -> float:
        """计算自适应滑点"""
        try:
            # 获取市场状态
            volatility = market_data.get('volatility', 0.02)
            volume = market_data.get('volume', 1000000)
            
            # 自适应滑点模型
            base_slippage = self.config.base_slippage_bps / 10000
            volatility_adjustment = volatility * 0.5
            volume_adjustment = min(0.01, 1000000 / volume * 0.001)
            
            total_slippage_rate = base_slippage * (1 + volatility_adjustment + volume_adjustment)
            
            return order.order_value * total_slippage_rate
            
        except Exception as e:
            logger.error(f"❌ 计算自适应滑点失败: {e}")
            return 0.0
    
    def _calculate_market_impact_cost(self, order: Order, market_data: Dict = None) -> float:
        """计算市场冲击成本"""
        try:
            if not market_data:
                return 0.0
            
            daily_volume = market_data.get('volume', 1000000)
            order_volume = order.quantity
            
            # 计算订单占日成交量比例
            volume_ratio = order_volume / daily_volume
            
            # 如果订单量很小，冲击成本可以忽略
            if volume_ratio < self.config.liquidity_threshold:
                return 0.0
            
            # 临时冲击成本（交易时的价格冲击）
            temporary_impact = (volume_ratio ** 0.5) * self.config.temporary_impact_factor
            
            # 永久冲击成本（对后续价格的持续影响）
            permanent_impact = (volume_ratio ** 0.3) * self.config.permanent_impact_factor
            
            # 总冲击成本
            total_impact_rate = (temporary_impact + permanent_impact) / 10000
            
            return order.order_value * total_impact_rate
            
        except Exception as e:
            logger.error(f"❌ 计算市场冲击成本失败: {e}")
            return 0.0
    
    def apply_slippage_to_price(self, order: Order, market_data: Dict = None) -> float:
        """对价格应用滑点"""
        try:
            cost_result = self.calculate_transaction_cost(order, market_data)
            
            # 计算滑点对价格的影响
            slippage_per_share = cost_result.slippage_cost / order.quantity
            
            if order.side == OrderSide.BUY:
                # 买入时价格上升
                return order.price + slippage_per_share
            else:
                # 卖出时价格下降
                return order.price - slippage_per_share
                
        except Exception as e:
            logger.error(f"❌ 应用滑点失败: {e}")
            return order.price
    
    def estimate_daily_trading_cost(self, orders: List[Order], market_data_dict: Dict = None) -> Dict[str, Any]:
        """估算日交易成本"""
        try:
            total_cost = 0.0
            total_value = 0.0
            cost_breakdown = {
                'commission': 0.0,
                'stamp_tax': 0.0,
                'transfer_fee': 0.0,
                'slippage_cost': 0.0,
                'market_impact_cost': 0.0
            }
            
            order_costs = []
            
            for order in orders:
                market_data = market_data_dict.get(order.stock_code) if market_data_dict else None
                cost_result = self.calculate_transaction_cost(order, market_data)
                
                total_cost += cost_result.total_cost
                total_value += order.order_value
                
                # 累计成本分解
                cost_breakdown['commission'] += cost_result.commission
                cost_breakdown['stamp_tax'] += cost_result.stamp_tax
                cost_breakdown['transfer_fee'] += cost_result.transfer_fee
                cost_breakdown['slippage_cost'] += cost_result.slippage_cost
                cost_breakdown['market_impact_cost'] += cost_result.market_impact_cost
                
                order_costs.append({
                    'stock_code': order.stock_code,
                    'side': order.side.value,
                    'cost': cost_result.total_cost,
                    'cost_bps': cost_result.cost_bps
                })
            
            # 计算平均成本率
            avg_cost_rate = total_cost / total_value if total_value > 0 else 0
            avg_cost_bps = avg_cost_rate * 10000
            
            return {
                'total_cost': total_cost,
                'total_value': total_value,
                'avg_cost_rate': avg_cost_rate,
                'avg_cost_bps': avg_cost_bps,
                'cost_breakdown': cost_breakdown,
                'order_costs': order_costs,
                'orders_count': len(orders)
            }
            
        except Exception as e:
            logger.error(f"❌ 估算日交易成本失败: {e}")
            return {}
    
    def optimize_order_execution(self, order: Order, market_data: Dict = None) -> Dict[str, Any]:
        """优化订单执行（拆分大订单）"""
        try:
            if not market_data:
                return {'optimized': False, 'reason': '缺少市场数据'}
            
            daily_volume = market_data.get('volume', 1000000)
            volume_ratio = order.quantity / daily_volume
            
            # 如果订单量超过日成交量的10%，建议拆分
            if volume_ratio > 0.1:
                # 计算建议的拆分数量
                max_order_size = int(daily_volume * 0.05)  # 每次最多5%
                split_count = math.ceil(order.quantity / max_order_size)
                
                split_orders = []
                remaining_quantity = order.quantity
                
                for i in range(split_count):
                    split_quantity = min(max_order_size, remaining_quantity)
                    split_order = Order(
                        stock_code=order.stock_code,
                        side=order.side,
                        quantity=split_quantity,
                        price=order.price,
                        timestamp=order.timestamp
                    )
                    split_orders.append(split_order)
                    remaining_quantity -= split_quantity
                
                return {
                    'optimized': True,
                    'original_cost_bps': self.calculate_transaction_cost(order, market_data).cost_bps,
                    'split_orders': split_orders,
                    'split_count': split_count,
                    'reason': f'大订单拆分，原订单占日成交量{volume_ratio:.1%}'
                }
            
            return {'optimized': False, 'reason': '订单大小合理，无需拆分'}
            
        except Exception as e:
            logger.error(f"❌ 优化订单执行失败: {e}")
            return {'optimized': False, 'reason': f'优化失败: {e}'}
    
    def update_config(self, new_config: TradingCostConfig):
        """更新配置"""
        self.config = new_config
        logger.info("✅ 交易成本配置已更新")
    
    def get_cost_summary(self) -> Dict[str, Any]:
        """获取成本配置摘要"""
        return {
            'commission_rate': self.config.commission_rate,
            'stamp_tax_rate': self.config.stamp_tax_rate,
            'transfer_fee_rate': self.config.transfer_fee_rate,
            'base_slippage_bps': self.config.base_slippage_bps,
            'slippage_model': self.config.slippage_model.value,
            'volume_impact_factor': self.config.volume_impact_factor
        }

# 使用示例
if __name__ == "__main__":
    # 创建交易成本模拟器
    config = TradingCostConfig(
        commission_rate=0.0003,  # 万三佣金
        base_slippage_bps=2.0,   # 2个基点滑点
        slippage_model=SlippageModel.LINEAR
    )
    
    simulator = TradingCostSimulator(config)
    
    # 创建测试订单
    test_order = Order(
        stock_code="000001",
        side=OrderSide.BUY,
        quantity=1000,
        price=10.50,
        timestamp=datetime.now()
    )
    
    # 模拟市场数据
    market_data = {
        'volume': 5000000,  # 日成交量
        'bid_ask_spread': 0.02,  # 买卖价差
        'volatility': 0.025  # 波动率
    }
    
    # 计算交易成本
    cost_result = simulator.calculate_transaction_cost(test_order, market_data)
    
    print(f"✅ 交易成本计算完成:")
    print(f"   佣金: {cost_result.commission:.2f}元")
    print(f"   印花税: {cost_result.stamp_tax:.2f}元")
    print(f"   过户费: {cost_result.transfer_fee:.2f}元")
    print(f"   滑点成本: {cost_result.slippage_cost:.2f}元")
    print(f"   冲击成本: {cost_result.market_impact_cost:.2f}元")
    print(f"   总成本: {cost_result.total_cost:.2f}元 ({cost_result.cost_bps:.2f}bps)")
    print(f"   有效价格: {cost_result.effective_price:.2f}元")
